﻿/**************************************************************
 *
 * 唯一标识：0ac2074a-fa91-48d2-addf-9c8a7ed85af0
 * 命名空间：Sgr.Generator.Segment
 * 创建时间：2024/6/20 11:04:14
 * 机器名称：DESKTOP-HJ4OAG9
 * 创建者：CocoYuan
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using Sgr.Threading;

namespace Sgr.Generator.Segment
{
    /// <summary>
    /// 表示一个生成段，用于生成唯一标识符。
    /// 剩余量低于阈值时触发预加载（默认：使用量超过20%）。
    /// </summary>
    public class GenSegment
    {
        private readonly AtomicLong _value;
        private readonly GenSegmentBuffer _buffer;
        private readonly AtomicLong _max;                   // 使用AtomicLong保证线程安全
        private int _step;                                  // 步长通常设置后不会变更

        /// <summary>
        /// 初始化 <see cref="GenSegment"/> 类的新实例。
        /// </summary>
        /// <param name="buffer">生成段缓冲区。</param>
        public GenSegment(GenSegmentBuffer buffer)
        {
            _buffer = buffer ?? throw new ArgumentNullException(nameof(buffer));

            _value = new AtomicLong(0);
            _max = new AtomicLong(0);
            _step = 0;
        }

        /// <summary>
        /// 设置当前生成段的值。
        /// </summary>
        /// <param name="value">要设置的值。</param>
        public void SetValue(long value) => _value.Set(value);

        /// <summary>
        /// 获取或设置当前生成段的最大值
        /// </summary>
        public long Max
        {
            get => _max.Get();
            set => _max.Set(value);
        }

        /// <summary>
        /// 获取或设置当前生成段的步长
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">步长小于1时抛出</exception>
        public int Step
        {
            get => Volatile.Read(ref _step);
            set
            {
                if (value < 1) throw new ArgumentOutOfRangeException(nameof(value), "步长必须大于0");
                Volatile.Write(ref _step, value);
            }
        }

        /// <summary>
        /// 将值增加 1 并返回新值
        /// </summary>
        /// <returns></returns>
        public long PreIncrementValue() => _value.PreIncrement();

        /// <summary>
        /// 获取生成段缓冲区。
        /// </summary>
        /// <returns>生成段缓冲区。</returns>
        public GenSegmentBuffer GetBuffer() => _buffer;

        /// <summary>
        /// 检查当前号段的使用比率是否已达到阈值
        /// </summary>
        /// <returns>如果达到阈值则返回True，否则返回false</returns>
        public bool CheckUseRate()
        {
            int currentStep = Step;
            if (currentStep <= 0)
                return false; // 未初始化步长，直接返回不触发预加载

            long idle = GetIdle();
            if (idle < 0) idle = 0; // 防御：避免越界导致负数逻辑异常

            return (idle * 10L) < (currentStep * 8L); // 纯整数比较，避免浮点
        }

        /// <summary>
        /// 获取当前生成段的空闲值
        /// </summary>
        private long GetIdle()
        {
            long currentValue = _value.Get();
            long maxValue = Max;
            long diff = maxValue - currentValue;
            return diff > 0 ? diff : 0;
        }

        /// <summary>
        /// 重置生成段状态
        /// </summary>
        public void Reset()
        {
            _max.Set(0);
            _value.Set(0);
            Volatile.Write(ref _step, 0);
        }
    }
}